package scottb.flex;

import scottb.flex.event.FlexEvent;
import scottb.flex.event.FlexEventListener;
import scottb.flex.navigate.Navigator;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class FlexApplication extends JFrame {

    private static FlexApplication instance;

    private Navigator navigator = new Navigator();
    private ArrayList<FlexPopUp> popUpList = new ArrayList<FlexPopUp>();
    private Map<FlexPopUp, PopUpCloseListener> popUpCloseListeners = new HashMap<FlexPopUp, PopUpCloseListener>();

    public static FlexApplication create() {

        instance = new FlexApplication();
        return instance;
    }

    public static FlexApplication getInstance() {

        return instance;
    }

    private FlexApplication() {

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLocationByPlatform(true);

        navigator.setContainer(this);
    }

    public Navigator navigator() {
        return navigator;
    }

    public void addPopUp(FlexPopUp popUp) {

        popUpList.add(popUp);
        PopUpCloseListener closeListener = new PopUpCloseListener();
        popUpCloseListeners.put(popUp, closeListener);
        popUp.addListener(FlexEvent.CLOSE, closeListener);

        int newLayer = getLayeredPane().highestLayer();

        if(newLayer < JLayeredPane.POPUP_LAYER) {
            newLayer = JLayeredPane.POPUP_LAYER;
        }

        enableLayersBelow(newLayer, false);

        popUp.setBounds(0, 0, getWidth(), getHeight());

        getLayeredPane().add(popUp, new Integer(newLayer));
    }

    class PopUpCloseListener implements FlexEventListener {

        public void flexEvent(FlexEvent event) {

            FlexPopUp popUp = (FlexPopUp) event.getSource();

            removePopUp(popUp);
        }
    }

    public void removePopUp(FlexPopUp popUp) {

        popUpList.remove(popUp);
        PopUpCloseListener closeListener = popUpCloseListeners.remove(popUp);
        popUp.removeListener(closeListener);

        int layer = getLayeredPane().getLayer(popUp);

        enableLayersBelow(layer, true);

        getLayeredPane().remove(popUp);
    }

    public void showWait() {
        // TODO
    }

    public void endWait() {
        // TODO
    }

    private void enableLayersBelow(int layer, boolean enabled) {

        JLayeredPane layers = getLayeredPane();

        for(Component c : layers.getComponents()) {

            if(layers.getLayer(c) < layer) {

                enableComponent(c, enabled);
            }
        }
    }

	private void enableComponent(final Component component, final boolean enabled)
	{
		component.setEnabled(enabled);

		if (component instanceof Container) {

			Container container = (Container) component;

			for (Component child : container.getComponents()) {

				enableComponent(child, enabled);
			}
		}
	}

    public FlexApplication add(Component c) {
        getContentPane().add(c);
        return this;
    }

    public void remove(Component c) {
        getContentPane().remove(c);
    }

    public void paint(Graphics g) {

        for(FlexPopUp popUp : popUpList) {

            popUp.setBounds(0, 0, getWidth(), getHeight());
        }

        super.paint(g);
    }
}
